//////////////////////////////////////////////////////////////////////////////////
//                                                                              //
//  This file is part of the buola project (https://code.google.com/p/buola/).  //
//                                                                              //
//  Copyright(c) 2007-2013 Xavi Gratal                                          //
//  gratal AT gmail DOT com                                                     //
//                                                                              //
//  Buola is free software: you can redistribute it and/or modify               //
//  it under the terms of the GNU General Public License as published by        //
//  the Free Software Foundation, either version 3 of the License, or           //
//  (at your option) any later version.                                         //
//                                                                              //
//  Buola is distributed in the hope that it will be useful,                    //
//  but WITHOUT ANY WARRANTY; without even the implied warranty of              //
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               //
//  GNU General Public License for more details.                                //
//                                                                              //
//  You should have received a copy of the GNU General Public License           //
//  along with buola.  If not, see <http://www.gnu.org/licenses/>.              //
//                                                                              //
//////////////////////////////////////////////////////////////////////////////////

#ifndef _BUOLA_AUTO_STRING_VIEW_H_
#define _BUOLA_AUTO_STRING_VIEW_H_

#include <string>

namespace buola {

///\addtogroup string
///@{

template<typename tChar,typename tTraits=std::char_traits<tChar>>
class basic_string_view
{
public:
    //standard STL container boilerplate
    typedef std::basic_string<tChar,tTraits> TString;
    typedef size_t size_type;
    typedef typename TString::value_type value_type;
    typedef const value_type* pointer;
    typedef const value_type& reference;
    typedef const value_type& const_reference;
    typedef ptrdiff_t difference_type;
    typedef const value_type* const_iterator;
    typedef std::reverse_iterator<const_iterator> const_reverse_iterator;

    static const size_type npos=TString::npos;

public:
    basic_string_view()
        :   mPtr(nullptr)
        ,   mLength(0)
    {}

    basic_string_view(const value_type* pStr)
        :   mPtr(pStr)
        ,   mLength(pStr?TString::traits_type::length(pStr):0) 
    {}
    
    basic_string_view(const TString &pStr)
        :   mPtr(pStr.data())
        ,   mLength(pStr.size())
    {}

    basic_string_view(const value_type* pStr,int pLength)
        :   mPtr(pStr)
        ,   mLength(pLength) 
    {}

    basic_string_view(typename TString::const_iterator pB,typename TString::const_iterator pE)
        :   mPtr((pE>pB)?&*pB:nullptr)
        ,   mLength((pE>pB)?(pE-pB):0)
    {}

    const value_type* data() const  {   return mPtr;        }
    size_type size() const          {   return mLength;     }
    size_type length() const        {   return mLength;     }
    bool empty() const              {   return mLength==0;  }

    void clear() 
    {
        mPtr=nullptr;
        mLength=0;
    }

    value_type operator[](size_type i) const    { return mPtr[i]; }

    void remove_prefix(size_type pN) 
    {
        mPtr+=pN;
        mLength-=pN;
    }

    void remove_suffix(size_type pN) 
    {
        mLength-=pN;
    }

    int compare(const basic_string_view &pRH) const 
    {
        int r=tTraits::compare(mPtr,pRH.mPtr,mLength<pRH.mLength?mLength:pRH.mLength);

        if (r == 0) 
        {
            if(mLength<pRH.mLength) return -1;
            if(mLength>pRH.mLength) return +1;
        }
        
        return r;
    }

    explicit operator TString() const
    {
        return empty()?TString():TString(data(),size());
    }

    const_iterator begin() const            {   return mPtr;            }
    const_iterator end() const              {   return mPtr+mLength;    }
    const_reverse_iterator rbegin() const   {   return const_reverse_iterator(mPtr+mLength);    }
    const_reverse_iterator rend() const     {   return const_reverse_iterator(mPtr);            }

    basic_string_view substr(size_type pPos,size_type pN=npos) const 
    {
        if(pPos>mLength) return basic_string_view();
        if(pN>mLength-pPos) pN=mLength-pPos;
        return basic_string_view(mPtr+pPos,pN);
    }

private:
    const value_type *mPtr;
    size_type mLength;
};

template<typename tChar,typename tTraits>
bool operator==(const basic_string_view<tChar,tTraits> &pLH,const basic_string_view<tChar,tTraits> &pRH)
{
    if(pLH.length()!=pRH.length()) return false;
    
    return tTraits::compare(pLH.data(),pRH.data(),pLH.length())==0;
}

template<typename tChar,typename tTraits>
inline bool operator!=(const basic_string_view<tChar,tTraits> &pLH,const basic_string_view<tChar,tTraits> &pRH)
{
    return !(pLH==pRH);
}

template<typename tChar,typename tTraits>
bool operator==(const basic_string_view<tChar,tTraits> &pLH,const std::basic_string<tChar,tTraits> &pRH)
{
    if(pLH.length()!=pRH.length()) return false;
    
    return tTraits::compare(pLH.data(),pRH.data(),pLH.length())==0;
}

template<typename tChar,typename tTraits>
bool operator==(const std::basic_string<tChar,tTraits> &pLH,const basic_string_view<tChar,tTraits> &pRH)
{
    if(pLH.length()!=pRH.length()) return false;
    
    return tTraits::compare(pLH.data(),pRH.data(),pLH.length())==0;
}

template<typename tChar,typename tTraits>
inline bool operator!=(const basic_string_view<tChar,tTraits> &pLH,const std::basic_string<tChar,tTraits> &pRH)
{
    return !(pLH==pRH);
}

template<typename tChar,typename tTraits>
inline bool operator!=(const std::basic_string<tChar,tTraits> &pLH,const basic_string_view<tChar,tTraits> &pRH)
{
    return !(pLH==pRH);
}

template<typename tChar,typename tTraits>
bool operator==(const basic_string_view<tChar,tTraits> &pLH,const tChar *pRH)
{
    if(pLH.length()!=tTraits::length(pRH)) return false;
    
    return tTraits::compare(pLH.data(),pRH,pLH.length())==0;
}

template<typename tChar,typename tTraits>
bool operator==(const tChar *pLH,const basic_string_view<tChar,tTraits> &pRH)
{
    if(tTraits::length(pLH)!=pRH.length()) return false;
    
    return tTraits::compare(pLH,pRH.data(),pRH.length())==0;
}

template<typename tChar,typename tTraits>
inline bool operator!=(const basic_string_view<tChar,tTraits> &pLH,const tChar *pRH)
{
    return !(pLH==pRH);
}

template<typename tChar,typename tTraits>
inline bool operator!=(const tChar *pLH,const basic_string_view<tChar,tTraits> &pRH)
{
    return !(pLH==pRH);
}

template<typename tChar,typename tTraits>
bool operator<(const basic_string_view<tChar,tTraits> &pLH,const basic_string_view<tChar,tTraits> &pRH)
{
    return pLH.compare(pRH)<0;
}

template<typename tChar,typename tTraits>
inline bool operator>(const basic_string_view<tChar,tTraits> &pLH,const basic_string_view<tChar,tTraits> &pRH)
{
    return pRH<pLH;
}

template<typename tChar,typename tTraits>
inline bool operator<=(const basic_string_view<tChar,tTraits> &pLH,const basic_string_view<tChar,tTraits> &pRH)
{
    return !(pRH<pLH);
}

template<typename tChar,typename tTraits>
inline bool operator>=(const basic_string_view<tChar,tTraits> &pLH,const basic_string_view<tChar,tTraits> &pRH)
{
    return !(pLH<pRH);
}

template<typename tChar,typename tTraits>
inline std::basic_string<tChar,tTraits> &operator+=(std::basic_string<tChar,tTraits> &pLH,
                                                    const basic_string_view<tChar,tTraits> &pRH)
{
    pLH.append(pRH.data(),pRH.length());
    return pLH;
}

typedef basic_string_view<char> string_view;
typedef basic_string_view<wchar_t> wstring_view;

///\todo add hash functions for basic_string_view

///@}

/*namespace buola*/ }

#endif
